package com.supreme.consumerserver.service;

import com.alibaba.fastjson.JSONObject;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class ElasticsearchService {

    private final RestHighLevelClient restHighLevelClient;

    @Autowired
    public ElasticsearchService(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    public boolean createIndex(String indexName) throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
        CreateIndexResponse response = this.restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }

    public List<String> searchIndex() throws IOException {
        GetAliasesRequest getAliasesRequest = new GetAliasesRequest();
        GetAliasesResponse aliasesResponse = this.restHighLevelClient.indices().getAlias(getAliasesRequest, RequestOptions.DEFAULT);
        Map<String, Set<AliasMetadata>> responseAliases = aliasesResponse.getAliases();
        return new ArrayList<>(responseAliases.keySet());
    }

    public boolean existIndex(String indexName) throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        return this.restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }

    public boolean deleteIndex(String indexName) throws IOException {
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
        AcknowledgedResponse response = this.restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }

    public <TE> int createDocument(String indexName, TE docData) throws IOException {
        IndexRequest indexRequest = new IndexRequest(indexName);
        indexRequest.source(JSONObject.toJSONString(docData), XContentType.JSON);
        IndexResponse indexResponse = this.restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        return indexResponse.status().getStatus();
    }

    public <TE> int createDocument(String indexName, TE docData, String documentId) throws IOException {
        IndexRequest indexRequest = new IndexRequest(indexName);
        if (documentId != null) {
            indexRequest.id(documentId);
        }

        indexRequest.source(JSONObject.toJSONString(docData), XContentType.JSON);
        IndexResponse indexResponse = this.restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        return indexResponse.status().getStatus();
    }

    public <TE> boolean bulkCreateDocument(String indexName, List<TE> docList) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();

        for (TE docData : docList) {
            IndexRequest indexRequest = new IndexRequest(indexName).source(JSONObject.toJSONString(docData), XContentType.JSON);
            bulkRequest.add(indexRequest);
        }

        BulkResponse bulkResponse = this.restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return !bulkResponse.hasFailures();
    }

    public boolean existDocument(String indexName, String documentId) throws IOException {
        GetRequest getRequest = new GetRequest(indexName, documentId);
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        getRequest.storedFields("_none_");
        return this.restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
    }

    public <TE> List<TE> searchDocument(String indexName, Class<TE> clazz, Integer offset, Integer limit) throws IOException {
        SearchRequest searchRequest = new SearchRequest(indexName);
        //构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        MatchAllQueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
//        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("username", "user3");
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.from(offset);
        searchSourceBuilder.size(limit);

        searchRequest.source(searchSourceBuilder);

        List<TE> dataList = new ArrayList<>();
        try {
            SearchResponse searchResponse = this.restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            for (SearchHit documentFields : searchResponse.getHits().getHits()) {
                String sourceAsString = documentFields.getSourceAsString();
                TE parseObject = JSONObject.parseObject(sourceAsString, clazz);
                dataList.add(parseObject);
            }
        } catch (ElasticsearchStatusException e) {
            System.out.println(e.getMessage());
        }

        return dataList;
    }

    public <TE> int updateDocument(String indexName, String documentId, TE docData) throws IOException {
        UpdateRequest updateRequest = new UpdateRequest(indexName, documentId);
        updateRequest.doc(JSONObject.toJSONString(docData), XContentType.JSON);
        UpdateResponse updateResponse = this.restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        return updateResponse.status().getStatus();
    }

    public int deleteDocument(String indexName, String documentId) throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest(indexName, documentId);
        DeleteResponse deleteResponse = this.restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        return deleteResponse.status().getStatus();
    }
}